/**
 *博尔信基础开发平台
 *<br> 版权声明：厦门博尔信软件有限公司版权所有,违者必究
 *<br> Copyright:  Copyright (c) 2012
 *<br> Company:pearlsoft
 *<br> @author 蒋勇华
 *<br> 2012-5-7
 *<br> @version 1.0
 *————————————————————————————————————
 *修改记录
 *    修改者：
 *    修改时间：
 *    修改原因：
 *——————————————————————————————————————
 */
package com.pearlsoft.webapp.sysmgr.menu.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Service;

import com.pearlsoft.commons.utils.UUIDUtil;
import com.pearlsoft.ui.tree.domain.CheckBoxTreeNode;
import com.pearlsoft.ui.tree.domain.TreeNode;
import com.pearlsoft.util.StringUtils;
import com.pearlsoft.webapp.core.WebException;
import com.pearlsoft.webapp.core.dao.RecrodRowMapper;
import com.pearlsoft.webapp.core.dataset.Record;
import com.pearlsoft.webapp.core.service.BaseSimpleJdbcService;

/**
 *描述： 
 *
 * 
 */
@Service
public class MenuService extends BaseSimpleJdbcService{
	private final String generalFields=" {0}.MENU_ID, {0}.MENU_CODE, {0}.MENU_NAME, {0}.MENU_IMG_CLS,{0}.MENU_ORDER,{0}.MENU_TYPE,{0}.MENU_URL,{0}.MENU_PARENT_ID,{0}.C_STATUS,{0}.C_REMARK,{0}.MENU_HANDLER ";
	private final RecrodRowMapper generalRowMapper=MenuRowMapperHelper.generalRowMapper();
	
	/***
	 * 通过ID得到对象
	 * @param menuId
	 * @return
	 */
	public Record getById(String menuId){
		String sql = "SELECT "+StringUtils.format(generalFields, "m")+" FROM sys_menu m WHERE MENU_ID=:MENU_ID";
		Map<String,String> param = new HashMap<String,String>();
		param.put("MENU_ID", menuId);
		Record record = this.getBaseSimpleJdbcDao().queryOne(sql,param,generalRowMapper);
		return record;
	}
	
	public void save(Record record) throws WebException{
		String objId =(String)record.getValue("MENU_ID");
		String menuCode = (String)record.getValue("MENU_CODE");
		boolean isCodeDup = this.checkCodeDup(objId,menuCode );
		if( isCodeDup ){
			throw new WebException("菜单编码已经存在");
		}
		if(StringUtils.isBlank(objId)){
			this.insertRecord(record);
		}else{
			this.updateRecord(record);
		}
	}

	private void insertRecord(Record record)  {
		String parentId = (String) record.getValue("MENU_PARENT_ID");
		String id = UUIDUtil.get();
		int menuOrder = this.getNewMenuOrder(parentId);
		
		record.setValue("MENU_ID", id);
		record.setValue("MENU_ORDER", menuOrder+"");
		
		String sql = "insert into SYS_MENU(MENU_ID,MENU_CODE,MENU_NAME,MENU_IMG_CLS,MENU_ORDER,MENU_TYPE,MENU_URL,MENU_PARENT_ID,C_STATUS,C_REMARK,MENU_HANDLER) " +
				" values(:MENU_ID,:MENU_CODE,:MENU_NAME,:MENU_IMG_CLS,:MENU_ORDER,:MENU_TYPE,:MENU_URL,:MENU_PARENT_ID,:C_STATUS,:C_REMARK,:MENU_HANDLER)";
		Map<String, String> param = new HashMap<String, String>();
		param.put("MENU_ID", (String) record.getValue("MENU_ID"));
		param.put("MENU_CODE", (String) record.getValue("MENU_CODE"));
		param.put("MENU_NAME", (String) record.getValue("MENU_NAME"));
		param.put("MENU_IMG_CLS", (String) record.getValue("MENU_IMG_CLS"));
		param.put("MENU_ORDER", (String) record.getValue("MENU_ORDER"));
		param.put("MENU_TYPE", (String) record.getValue("MENU_TYPE"));
		param.put("MENU_URL", (String) record.getValue("MENU_URL"));
		param.put("MENU_PARENT_ID", (String) record.getValue("MENU_PARENT_ID"));
		param.put("C_STATUS", (String) record.getValue("C_STATUS"));
		param.put("C_REMARK", (String) record.getValue("C_REMARK"));
		param.put("MENU_HANDLER", (String) record.getValue("MENU_HANDLER"));
		this.getBaseSimpleJdbcDao().update(sql, param);
	}
	
	private void updateRecord( Record record)   {
		String sql = "update SYS_MENU set MENU_CODE=:MENU_CODE,MENU_NAME=:MENU_NAME," +
				"MENU_IMG_CLS=:MENU_IMG_CLS,MENU_ORDER=:MENU_ORDER,MENU_TYPE=:MENU_TYPE," +
				"MENU_URL=:MENU_URL,MENU_PARENT_ID=:MENU_PARENT_ID,C_STATUS=:C_STATUS," +
				"C_REMARK=:C_REMARK,MENU_HANDLER=:MENU_HANDLER where MENU_ID=:MENU_ID";
		Map<String, String> param = new HashMap<String, String>();
		param.put("MENU_CODE", (String) record.getValue("MENU_CODE"));
		param.put("MENU_NAME", (String) record.getValue("MENU_NAME"));
		param.put("MENU_IMG_CLS", (String) record.getValue("MENU_IMG_CLS"));
		param.put("MENU_ORDER", (String) record.getValue("MENU_ORDER"));
		param.put("MENU_TYPE", (String) record.getValue("MENU_TYPE"));
		param.put("MENU_URL", (String) record.getValue("MENU_URL"));
		param.put("MENU_PARENT_ID", (String) record.getValue("MENU_PARENT_ID"));
		param.put("C_STATUS", (String) record.getValue("C_STATUS"));
		param.put("C_REMARK", (String) record.getValue("C_REMARK"));
		param.put("MENU_HANDLER", (String) record.getValue("MENU_HANDLER"));
		param.put("MENU_ID", (String) record.getValue("MENU_ID"));
		this.getBaseSimpleJdbcDao().update(sql, param);
	}
	
	public void deleteById(String menuId) {
		String sql = "delete from SYS_MENU where MENU_ID=:MENU_ID";
		Map<String, String> param = new HashMap<String, String>();
		param.put("MENU_ID", menuId);
		this.getBaseSimpleJdbcDao().update(sql, param);
	}
	
	
	
	
	
	/***
	 * 得到新增菜单的序号
	 * @param parentId
	 * @return
	 */
	public int getNewMenuOrder(String parentId){
		String sql=" select count(*) from sys_menu where MENU_PARENT_ID =:MENU_PARENT_ID  ";
		Map<String,String> param = new HashMap<String,String>();
		param.put("MENU_PARENT_ID", parentId);
		return this.getBaseSimpleJdbcDao().queryForInt(sql,param)+1;
	}
	
	
	private Record getMenuByOrder(String parentId,int order){
		String sql = "SELECT "+StringUtils.format(generalFields, "m")+" FROM sys_menu m WHERE MENU_PARENT_ID=:MENU_PARENT_ID and MENU_ORDER =:MENU_ORDER";
		Map<String,String> param = new HashMap<String,String>();
		param.put("MENU_PARENT_ID", parentId);
		param.put("MENU_ORDER", order+"");
		Record record = this.getBaseSimpleJdbcDao().queryOne(sql,param,generalRowMapper);
		return record;
	}
	
	private void setMenuOrder(String menuId,int order){
		String sql ="update SYS_MENU set MENU_ORDER=:MENU_ORDER where MENU_ID =:MENU_ID";
		Map<String,String> param = new HashMap<String,String>();
		param.put("MENU_ORDER", order+"");
		param.put("MENU_ID", menuId);		
		this.getBaseSimpleJdbcDao().update(sql, param);
	}
	
	/**
	 * 上移动
	 * @param menuId
	 * @throws Exception
	 */
	public void menuUp(String menuId) throws Exception{
		Record currentMenu = this.getById(menuId);
		String parentId =(String)currentMenu.getValue("MENU_PARENT_ID");
		int order =(Integer)currentMenu.getValue("MENU_ORDER");
		Record upMenu = this.getMenuByOrder(parentId,order-1);
		if( upMenu ==null ){
			throw new WebException("已经是最顶端,不能上移");
		}else{
			String upMenuId = (String)upMenu.getValue("MENU_ID");
			this.setMenuOrder(menuId, order -1 ); 
			this.setMenuOrder(upMenuId, order);
		}
	}
	
	/***
	 * 下移
	 * @param menuId
	 * @throws Exception
	 */
	public void menuDown(String menuId) throws Exception{
		Record currentMenu = this.getById(menuId);
		String parentId =(String)currentMenu.getValue("MENU_PARENT_ID");
		int order =(Integer)currentMenu.getValue("MENU_ORDER");
		Record downMenu = this.getMenuByOrder(parentId,order+1);
		if( downMenu ==null ){
			throw new WebException("已经是最底端,不能下移");
		}else{
			String downMenuId = (String)downMenu.getValue("MENU_ID");
			this.setMenuOrder(menuId, order +1 ); 
			this.setMenuOrder(downMenuId, order);
		}
	}
	
	/***
	 * 获取用户拥有的所有菜单
	 * @param userId
	 * @return
	 */
	public List<Record> getUserMenulist(String userId){
		StringBuilder sqlbuffer = new StringBuilder();
		sqlbuffer.append("SELECT "+StringUtils.format(generalFields, "F")+" FROM ( ");
		sqlbuffer.append("SELECT DISTINCT(C.MENU_ID) FROM  ");
		sqlbuffer.append("	    (SELECT * FROM sys_user_role   WHERE USER_ID=:USER_ID) B  ");
		sqlbuffer.append("	    LEFT JOIN sys_role_menu C ON B.ROLE_ID = C.ROLE_ID  WHERE C.MENU_ID IS NOT NULL   ");
		sqlbuffer.append("	) D  ");
		sqlbuffer.append("	LEFT JOIN sys_menu F ON D.MENU_ID = F.MENU_ID  ");
		sqlbuffer.append("	WHERE F.C_STATUS='1' ORDER BY F.MENU_PARENT_ID,F.MENU_ORDER ");
		Map<String,String> param = new HashMap<String,String>();
		param.put("USER_ID", userId);
		List<Record> list = this.getBaseSimpleJdbcDao().query(sqlbuffer.toString(), param, generalRowMapper);
		return list;
	}
	
	/***
	 * 得到用户指定菜单下的按钮
	 * @param userId
	 * @param menuCode
	 * @return
	 * @throws WebException 
	 */
	public List<Record> getPageButtons(String userId,String menuCode) throws WebException{
		if(StringUtils.isBlank(userId) ){
			throw new WebException("没有获取用户Id");
		}
		if(StringUtils.isBlank(menuCode) ){
			throw new WebException("菜单编码不能为空");
		}		
		
		
		StringBuilder sqlbuffer = new StringBuilder();
		sqlbuffer.append(" SELECT "+StringUtils.format(generalFields, "G") +" FROM ( ");
		sqlbuffer.append("     SELECT F.* FROM ( ");
		sqlbuffer.append("         SELECT DISTINCT(C.MENU_ID) FROM  ");
		sqlbuffer.append("         (SELECT * FROM sys_user_role   WHERE USER_ID=:USER_ID) B  ");
		sqlbuffer.append("         LEFT JOIN sys_role_menu C ON B.ROLE_ID = C.ROLE_ID  WHERE C.MENU_ID IS NOT NULL   ");
		sqlbuffer.append("     ) D  ");
		sqlbuffer.append("     LEFT JOIN sys_menu F ON D.MENU_ID = F.MENU_ID  ");
		sqlbuffer.append("     WHERE F.C_STATUS='1' ORDER BY F.MENU_PARENT_ID,F.MENU_ORDER  ");
		sqlbuffer.append(" ) G ");
		sqlbuffer.append(" LEFT JOIN sys_menu H ON G.MENU_PARENT_ID = H.MENU_ID  ");
		sqlbuffer.append(" WHERE G.MENU_TYPE ='0'  AND G.C_STATUS='1' AND H.MENU_CODE =:MENU_CODE  ");
		sqlbuffer.append(" ORDER BY G.MENU_PARENT_ID,G.MENU_ORDER  ");
		Map<String,String> param = new HashMap<String,String>();
		param.put("USER_ID", userId);
		param.put("MENU_CODE", menuCode);
		List<Record> list = this.getBaseSimpleJdbcDao().query(sqlbuffer.toString(), param, generalRowMapper);		
		return list;
	}
	
	
	
	
	/***
	 * 得到父节点下面的菜单list
	 * @param parentId
	 * @return
	 */
	public List<Record> getChildern(String parentId){
		String sql=" select "+StringUtils.format(generalFields, "m")+" from sys_menu m where MENU_PARENT_ID =:MENU_PARENT_ID ORDER BY MENU_ORDER ";
		Map<String,String> param = new HashMap<String,String>();
		param.put("MENU_PARENT_ID", parentId);
		return this.getBaseSimpleJdbcDao().query(sql, param, generalRowMapper);
	}
	
	
	/***
	 * 检查是否有重复的菜单编码
	 * @param menuId
	 * @param menuCode
	 * @return
	 */
	public boolean checkCodeDup(String menuId,String menuCode){
		String sql ="";
		Map<String,String> params = new HashMap<String,String>();
		if( StringUtils.isBlank(menuId)){
			sql =" select count(*) from sys_menu where menu_code = :menu_code";
			params.put("menu_code", menuCode);
		}else{
			sql =" select count(*) from sys_menu where menu_code = :menu_code and menu_id <> :menu_id";
			params.put("menu_code", menuCode);
			params.put("menu_id", menuId);
		}
		int count = this.getBaseSimpleJdbcDao().queryForInt(sql, params);
		return count > 0 ? true:false;
	}
	
	/***
	 * 获取系统所有菜单的MAP
	 * @return
	 */
	public Map<String,CheckBoxTreeNode> sysMenu(){
		Map<String,CheckBoxTreeNode>  allMenu = new HashMap<String,CheckBoxTreeNode> ();
		String sql = "";
		Map<String,String> params = new HashMap<String,String>();
		sql="select distinct (menu.MENU_ID),menu.MENU_CODE ,menu.MENU_NAME,menu.MENU_IMG_CLS," +
			"menu.MENU_ORDER,menu.MENU_TYPE,menu.MENU_URL,menu.MENU_PARENT_ID,menu.C_STATUS,menu.C_REMARK,menu.MENU_HANDLER ";
		sql = sql + "from sys_menu menu " ;
		List<Record> menuList = this.getBaseSimpleJdbcDao().query(sql, params, generalRowMapper);
		if( menuList ==null || menuList.size()==0){
			return null;
		}
		for(Record recrod:menuList ){
			CheckBoxTreeNode treeNode = recrodToCheckBoxTreeNode(recrod);
			allMenu.put(treeNode.getId(), treeNode);
		}
		return allMenu;
	}
	
	/***
	 * 查询某用户拥有的所有菜单,返回菜单的Root节点
	 * @param userId
	 * @return
	 */
	public Record queryMenuTreeInUser(String userId){
		String sql = "";
		Map<String,String> params = new HashMap<String,String>();
		sql="select distinct (menu.MENU_ID),menu.MENU_CODE ,menu.MENU_NAME,menu.MENU_IMG_CLS," +
			"menu.MENU_ORDER,menu.MENU_TYPE,menu.MENU_URL,menu.MENU_PARENT_ID,menu.C_STATUS,menu.C_REMARK,menu.MENU_HANDLER ";
		sql = sql + "from sys_menu menu " ;
		sql = sql + "left  join sys_role_menu rm on menu.menu_id = rm.menu_id  " ;
		sql = sql + "left join sys_role role on rm.role_id = role.role_id  " ;
		sql = sql + "left join sys_user_role sur on  role.role_id = sur.role_id  " ;
		sql = sql + "where sur.user_id =:user_id " ;
		params.put("user_id", userId);
		List<Record> list = this.getBaseSimpleJdbcDao().query(sql, params, generalRowMapper);
		return menuListToTreeRoot(list);
	}
	
	/***
	 * 查询不再用户中的菜单，返回root节点
	 * @param userId
	 * @return
	 */
	public Record queryMenuTreeNotInUser(String userId){
		String sql = "";
		Map<String,String> params = new HashMap<String,String>();
		sql="select distinct (menu.MENU_ID),menu.MENU_CODE ,menu.MENU_NAME,menu.MENU_IMG_CLS," +
			"menu.MENU_ORDER,menu.MENU_TYPE,menu.MENU_URL,menu.MENU_PARENT_ID,menu.C_STATUS,menu.C_REMARK,menu.MENU_HANDLER ";
		sql = sql + "from sys_menu menu " ;
		sql = sql + "left  join sys_role_menu rm on menu.menu_id = rm.menu_id  " ;
		sql = sql + "left join sys_role role on rm.role_id = role.role_id  " ;
		sql = sql + "left join sys_user_role sur on  role.role_id = sur.role_id  " ;
		sql = sql + "where sur.user_id <>:user_id " ;
		params.put("user_id", userId);
		List<Record> list = this.getBaseSimpleJdbcDao().query(sql, params, generalRowMapper);
		return menuListToTreeRoot(list);		
	}
	
	/***
	 * 查询某角色拥有的系统菜单，返回菜单ROOT节点
	 * @param roleId
	 * @return
	 */
	public Record queryMenuTreeInRole(String roleId){
		String sql = "";
		Map<String,String> params = new HashMap<String,String>();
		sql="select distinct (menu.MENU_ID),menu.MENU_CODE ,menu.MENU_NAME,menu.MENU_IMG_CLS," +
			"menu.MENU_ORDER,menu.MENU_TYPE,menu.MENU_URL,menu.MENU_PARENT_ID,menu.C_STATUS,menu.C_REMARK,menu.MENU_HANDLER ";
		sql = sql + "from sys_menu menu " ;
		sql = sql + "left  join sys_role_menu rm on menu.menu_id = rm.menu_id  " ;
		sql = sql + "left join sys_role role on rm.role_id = role.role_id  " ;
		sql = sql + "where role.role_id =:role_id " ;
		params.put("role_id", roleId);
		List<Record> list = this.getBaseSimpleJdbcDao().query(sql, params, generalRowMapper);
		return menuListToTreeRoot(list);
	}
	/***
	 * 查询某角色没有的系统菜单，返回菜单root节点
	 * @param roleId
	 * @return
	 */
	public Record queryMenuTreeNotInRole(String roleId){
		String sql = "";
		String menuInRoleSql = "";
		Map<String,String> params = new HashMap<String,String>();
		
		menuInRoleSql="select distinct (menu.MENU_ID) ";
		menuInRoleSql = menuInRoleSql + "from sys_menu menu " ;
		menuInRoleSql = menuInRoleSql + "left  join sys_role_menu rm on menu.menu_id = rm.menu_id  " ;
		menuInRoleSql = menuInRoleSql + "left join sys_role role on rm.role_id = role.role_id  " ;
		menuInRoleSql = menuInRoleSql + "where role.role_id =:role_id " ;
		
		sql="select distinct (menu.MENU_ID),menu.MENU_CODE ,menu.MENU_NAME,menu.MENU_IMG_CLS," +
				"menu.MENU_ORDER,menu.MENU_TYPE,menu.MENU_URL,menu.MENU_PARENT_ID,menu.C_STATUS,menu.C_REMARK,menu.MENU_HANDLER ";
		sql = sql + "from sys_menu menu " ;
		sql = sql + "where menu.MENU_ID not in ("+menuInRoleSql+") " ;
		params.put("role_id", roleId);
		List<Record> list = this.getBaseSimpleJdbcDao().query(sql, params, generalRowMapper);
		return menuListToTreeRoot(list);
	}
	
	/***
	 * 把查询到的菜单记录转换成root菜单节点
	 * @param menuList
	 * @return
	 */
	private  Record menuListToTreeRoot(List<Record> menuList){
		if( menuList ==null || menuList.size()==0){
			return null;
		}
		Map<String,CheckBoxTreeNode> allMenu = this.sysMenu();
		CheckBoxTreeNode rootNode = new CheckBoxTreeNode();
		rootNode.setId("0");
		rootNode.setLeaf(false);
		rootNode.setChecked(false);
		rootNode.setIndex(1);
		rootNode.setLoaded(true);
		rootNode.setText("系统菜单");
		
		List<TreeNode> list = null;
		Map<String,List<TreeNode>> parentKeyMap = new HashMap<String,List<TreeNode>>();
		Map<String,TreeNode> keyMap = new HashMap<String,TreeNode>();
		
		for(Record recrod:menuList ){
			CheckBoxTreeNode treeNode = recrodToCheckBoxTreeNode(recrod);
			List<CheckBoxTreeNode> fullPathNodes =getFullPathNodes(treeNode,allMenu); 
			for(CheckBoxTreeNode node:fullPathNodes ){
				if( !keyMap.containsKey(node.getId()) ){
					keyMap.put(node.getId(), node);
					list = parentKeyMap.get(node.getParentId());
					if( list == null ){
						list = new ArrayList<TreeNode>();
						parentKeyMap.put(node.getParentId(), list);
					}
					list.add(node);
				}
				if( node.getParentId().equalsIgnoreCase("0")){
					//rootNode = node;
					rootNode.getChildren().add(node);
				}
			}
		}
		if( rootNode == null ){
			return null;
		}
		addChildren(rootNode,parentKeyMap);
		return rootNode;		
	}
	
	/***
	 * 返回该节点极其所有上级节点
	 * @param treeNode
	 * @param allMenu
	 * @return
	 */
	private  List<CheckBoxTreeNode> getFullPathNodes(CheckBoxTreeNode treeNode,Map<String,CheckBoxTreeNode> allMenu){
		List<CheckBoxTreeNode> nodes= new ArrayList<CheckBoxTreeNode>();
		nodes.add(treeNode);
		CheckBoxTreeNode parent = allMenu.get(treeNode.getParentId());
		while(parent!=null){
			nodes.add(parent);
			parent = allMenu.get(parent.getParentId());
		}
		return nodes;
	}
	
	
	private  void addChildren(TreeNode node,Map<String,List<TreeNode>> mapNode ){
		List<TreeNode> children = mapNode.get(node.getId());
		if( children != null && children.size() > 0 ){
			for( TreeNode child: children){
				addChildren(child,mapNode);
			}
			node.setChildren(children);
		}
	}
	
	private  CheckBoxTreeNode recrodToCheckBoxTreeNode(Record record){
		CheckBoxTreeNode treeNode = new CheckBoxTreeNode();
		treeNode.setId((String)record.getValue("MENU_ID"));
		treeNode.setText((String)record.getValue("MENU_NAME"));
		treeNode.setParentId((String)record.getValue("MENU_PARENT_ID"));
		treeNode.setIndex((Integer)record.getValue("MENU_ORDER"));
		String menuType =(String) record.getValue("MENU_TYPE");
		if(menuType!=null && menuType.equalsIgnoreCase("0")){
			treeNode.setLeaf(true);
		}
		Map<String,Object> attributes = new HashMap<String,Object>();
		attributes.put("MENU_CODE", (String)record.getValue("MENU_CODE"));
		attributes.put("MENU_IMG_CLS", (String)record.getValue("MENU_IMG_CLS"));
		attributes.put("MENU_TYPE", (String)record.getValue("MENU_TYPE"));
		attributes.put("MENU_URL", (String)record.getValue("MENU_URL"));
		treeNode.setAttributes(attributes);
		return treeNode;
	}
	
}
